import 'dart:async';
import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_ume_kit_mock/widgets/mock_inspector.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_ume_kit_mock/data/model/mock_history.dart';

import 'package:flutter_ume_kit_mock/data/feishu_api.dart';
import 'package:flutter_ume_kit_mock/data/model/case.dart';
import 'package:flutter_ume_kit_mock/data/model/list_data.dart';
import 'package:flutter_ume_kit_mock/data/model/mock.dart';
import 'package:flutter_ume_kit_mock/data/model/request.dart';
import 'package:flutter_ume_kit_mock/data/config_cache_manager.dart';
import 'package:flutter_ume_kit_mock/data/config_service.dart';

class MockConfigManager {
  static Map<String, Request> globalRequestMap = {};
  static Map<String, Mock> globalMockMap = {};

  static ValueNotifier<Set<String>> enableSetNotifier = ValueNotifier({});
  static ValueNotifier<List<MockCase>> caseListNotifier = ValueNotifier([]);
  static ValueNotifier<List<Mock>> mockListNotifier = ValueNotifier([]);

  //mock历史
  static final StreamController<MockHistory> triggerStreamController = StreamController.broadcast();
  static ValueNotifier<List<MockHistory>> mockHistoryNotifier = ValueNotifier([]);

  static final Completer<bool> _configCompleter = Completer();

  static ConfigService<MockCase> caseService = ConfigService(
      CacheType.Case, 'bascnFg8E7UG8SHmy3g59SxwOZc', 'tblKFkCO3M3uDJ3F',
      (json) {
    return ListData<MockCase>.fromJson(json, (json) => MockCase.fromJson(json));
  });

  static ConfigService<Mock> mockService = ConfigService(
      CacheType.Mock, 'bascnFg8E7UG8SHmy3g59SxwOZc', 'tblSYEK3aZyHi8GI',
      (json) {
    return ListData<Mock>.fromJson(json, (json) => Mock.fromJson(json));
  });

  static ConfigService<Request> requestService = ConfigService(
      CacheType.Request, 'bascnFg8E7UG8SHmy3g59SxwOZc', 'tblu8Df4SE3rda4s',
      (json) {
    return ListData<Request>.fromJson(json, (json) => Request.fromJson(json));
  });

  ///初始化配置信息
  static void initConfigs(Dio dio, String feishuAppId, String feishuAppSecret) {
    //先读缓存，没有的话，再请求网络
    readCacheConfigs().then((value) {
      print("${MockInspector.TAG} read cache result $value");
      if (!_configCompleter.isCompleted) {
        _configCompleter.complete(value);
      }
      if (!value) {
        fetchMockConfig(dio, feishuAppId, feishuAppSecret);
      }
    });
    triggerStreamController.stream.listen((event) {
      mockHistoryNotifier.value.insert(0, event);
      mockHistoryNotifier.notifyListeners();
    });
  }

  static Future waitCompleteInitConfig() {
    return _configCompleter.future;
  }

  static Future<bool> readCacheConfigs() async {
    var caseList = await caseService.readCache();
    var mockList = await mockService.readCache();
    var requestList = await requestService.readCache();
    if (caseList == null || mockList == null || requestList == null) {
      return false;
    }
    await resetConfigs(caseList, mockList, requestList);
    return true;
  }

  static Future<bool> fetchMockConfig(
      Dio dio, String feishuAppId, String feishuAppSecret) async {
    print("${MockInspector.TAG} start fetch mock config");
    try {
      String? token = await FeishuApi.fetchTenantAccessToken(
          dio, feishuAppId, feishuAppSecret);
      print("${MockInspector.TAG} token = ${token}");
      if (token == null) {
        return false;
      }
      var caseList = await caseService.fetchMockConfig(dio, token);
      var mockList = await mockService.fetchMockConfig(dio, token);
      var requestList = await requestService.fetchMockConfig(dio, token);
      if (requestList == null || mockList == null || caseList == null) {
        return false;
      }
      print("${MockInspector.TAG} fetch finish");
      await resetConfigs(caseList, mockList, requestList);
      return true;
    } catch (e, s) {
      print("${MockInspector.TAG} fetch error ${e.toString()} ${s.toString()}");
      return false;
    }
  }

  static Future resetConfigs(List<MockCase> caseList, List<Mock> mockList,
      List<Request> requestList) async {
    List<dynamic>? enables = await readEnableCache();
    print("${MockInspector.TAG} enables list = ${jsonEncode(enables)}");
    if (enables != null) {
      for (var element in enables) {
        enableSetNotifier.value.add(element);
      }
      enableSetNotifier.notifyListeners();
    }

    globalRequestMap.clear();
    globalMockMap.clear();

    for (var element in requestList) {
      globalRequestMap[element.id ?? ''] = element;
    }

    //mock
    for (var mock in mockList) {
      mock.fields?.request?.forEach((mockRequest) {
        mockRequest.record_ids?.forEach((recordId) {
          var request = globalRequestMap[recordId];
          if (request != null) {
            mock.request = request;
          }
        });
      });
      mock.enable = enableSetNotifier.value.contains(mock.id);
      globalMockMap[mock.id ?? ''] = mock;
    }
    mockListNotifier.value = mockList;

    //case
    for (var mockCase in caseList) {
      List<Mock> list = [];
      mockCase.fields?.mock?.forEach((caseMock) {
        caseMock.record_ids?.forEach((recordId) {
          var mock = globalMockMap[recordId];
          if (mock != null) {
            list.add(mock);
          }
        });
      });
      mockCase.enable = enableSetNotifier.value.contains(mockCase.id);
      mockCase.mocks = list;
    }
    caseListNotifier.value = caseList;
  }

  ///检查是否发生了冲突
  ///return true:有冲突   false:无冲突
  static bool checkEnableConflict({MockCase? mockCase, Mock? mock}) {
    List<Mock> checkMocks = [];
    if (mockCase?.mocks != null) {
      checkMocks.addAll(mockCase!.mocks!);
    }
    if (mock != null) {
      checkMocks.add(mock);
    }
    for (var caseElement in caseListNotifier.value) {
      if (caseElement.enable && caseElement.mocks != null) {
        for (var mockElement in caseElement.mocks!) {
          for (var checkMock in checkMocks) {
            if (checkMock.isConflictWithAnother(mockElement)) {
              Fluttertoast.showToast(
                  gravity: ToastGravity.CENTER,
                  msg:
                      "与 ${caseElement.fields?.title} 的 ${mockElement.fields?.title} 冲突");
              return true;
            }
          }
        }
      }
    }
    for (var mockElement in mockListNotifier.value) {
      if (mockElement.enable) {
        for (var checkMock in checkMocks) {
          if (checkMock.isConflictWithAnother(mockElement)) {
            Fluttertoast.showToast(
                gravity: ToastGravity.CENTER,
                msg: "与 ${mockElement.fields?.title} 冲突");
            return true;
          }
        }
      }
    }
    return false;
  }

  static void addEnable(String? id) {
    if (id == null) {
      return;
    }
    enableSetNotifier.value.add(id);
    enableSetNotifier.notifyListeners();
    writeEnableCache(enableSetNotifier.value.toList(growable: false));
  }

  static void removeEnable(String? id) {
    enableSetNotifier.value.remove(id);
    enableSetNotifier.notifyListeners();
    writeEnableCache(enableSetNotifier.value.toList(growable: false));
  }

  static Future<List<dynamic>?> readEnableCache() async {
    try {
      String? enables = await ConfigCacheManager.readCache(CacheType.Enables);
      print("${MockInspector.TAG} enables json = ${enables}");
      if (enables == null) {
        return null;
      }
      return jsonDecode(enables);
    } catch (e) {
      print("${MockInspector.TAG} ${e}");
      return null;
    }
  }

  static writeEnableCache(List<String> enables) {
    ConfigCacheManager.writeCache(CacheType.Enables, jsonEncode(enables));
  }
}
